/**
 * 
 */
package com.jszw.bcp.kernal.log;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author zhengzw
 *
 */
@Aspect
@Component
public class TraceLogAspect {
	private ThreadLocal<Long> threadLocal = new ThreadLocal<Long>();

	@Pointcut(value = "@annotation(com.jszw.bcp.kernal.log.TraceLog)")
	public void traceLogging() {

	}

	@Around(value = "traceLogging() && @annotation(log)")
	public Object trace(ProceedingJoinPoint point, TraceLog log) throws Throwable {

		Class<? extends Object> clazz = point.getTarget().getClass();
		Method method = extractMethod(point);
		Logger logger = getLog(clazz);

		Date start = new Date();
		threadLocal.set(start.getTime());

		logger.info("程序轨迹跟踪-->方法:[" + clazz.getName() + "." + method.getName() + "] 描述:["
				+ log.value() + "] 开始:[" + dateToStr(start) + "]");

		// 为了防止日志打印时间相同, proceed前睡1毫秒
		Thread.sleep(1);
		
		Object object = point.proceed();
		
		// 为了防止日志打印时间相同, proceed后睡1毫秒
		Thread.sleep(1);
		
		Date end = new Date();
		
		logger.info("程序轨迹跟踪-->方法:[" + clazz.getName() + "." + method.getName() + "] 描述:["
				+ log.value() + "] 结束:[" + dateToStr(end) + "] 持续:[" + (end.getTime()-threadLocal.get()) + "] 毫秒");
		
		return object;
	}

	@SuppressWarnings("unused")
	private HttpServletRequest getRequest() {
		ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		return ra.getRequest();
	}

	private Logger getLog(Class<?> clazz) {
		return LoggerFactory.getLogger(clazz);
	}

	private Method extractMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Class<?> targetClass = joinPoint.getTarget().getClass();

		if (Modifier.isPublic(signature.getMethod().getModifiers())) {
			return targetClass.getMethod(signature.getName(), signature.getParameterTypes());
		} else {
			return ReflectionUtils.findMethod(targetClass, signature.getName(), signature.getParameterTypes());
		}
	}

	private String dateToStr(Date date) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
		String str = format.format(date);
		return str;
	}
}
